#pragma once

#include <string>
#include <vector>
#include <memory>
#include "rtda/heap/access_flags.h"
#include "classfile/class_file.hpp"

namespace jvm {
namespace heap {

class ClassLoader;
class ConstantPool;
class Field;
class Method;
class Object;
class Slots;

class Class {
private:
    uint16_t m_accessFlags;
    std::string m_name; // thisClassName
    std::string m_superClassName;
    std::vector<std::string> m_interfaceNames;
    std::shared_ptr<ConstantPool> m_pConstantPool;
    std::vector<std::shared_ptr<Field>> m_fields;
    std::vector<std::shared_ptr<Method>> m_methods;
    std::shared_ptr<ClassLoader> m_pLoader;
    std::shared_ptr<Class> m_pSuperClass;
    std::vector<std::shared_ptr<Class>> m_interfaces;
    uint m_instanceSlotCount;
    uint m_staticSlotCount;
    std::shared_ptr<Slots> m_pStaticVars;

public:
    Class(std::shared_ptr<classfile::ClassFile> pClassFile);
    
    // Access flags
    bool isPublic() const;
    bool isFinal() const;
    bool isSuper() const;
    bool isInterface() const;
    bool isAbstract() const;
    bool isSynthetic() const;
    bool isAnnotation() const;
    bool isEnum() const;

    // Getters
    std::shared_ptr<ConstantPool> getConstantPool() const;
    std::shared_ptr<Slots> getStaticVars() const;

    // Class operations
    bool isAccessibleTo(std::shared_ptr<Class> pOther) const;
    std::string getPackageName() const;
    std::shared_ptr<Method> getMainMethod() const;
    std::shared_ptr<Method> getStaticMethod(const std::string& name, const std::string& descriptor) const;
    std::shared_ptr<Object> newObject() const;

    // Class hierarchy operations
    bool isAssignableFrom(std::shared_ptr<Class> pOther) const;
    bool isSubClassOf(std::shared_ptr<Class> pOther) const;
    bool isImplements(std::shared_ptr<Class> pIface) const;
    bool isSubInterfaceOf(std::shared_ptr<Class> pIface) const;
};

} // namespace heap
} // namespace jvm
